﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using GxTsSharp.Models;

namespace GxTsSharp
{
    public class Eagle
    {
        private bool _isInit = false;
        private bool _isLogin = false;

        public Eagle()
        {
            var pFile = "Eagle.dll";
            _handle = LoadLibrary(pFile);
            if (_handle == IntPtr.Zero)
            {
                throw (new Exception(string.Format("没有找到：" + Environment.CurrentDirectory + "\\" + pFile)));
            }
            
        }
        
        /// <summary>
        ///     原型是 :HMODULE LoadLibrary(LPCTSTR lpFileName);
        /// </summary>
        /// <param name="lpFileName"> DLL 文件名 </param>
        /// <returns> 函数库模块的句柄 </returns>
        [DllImport("kernel32.dll")]
        private static extern IntPtr LoadLibrary(string lpFileName);

        /// <summary>
        ///     原型是 : FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);
        /// </summary>
        /// <param name="hModule"> 包含需调用函数的函数库模块的句柄 </param>
        /// <param name="lpProcName"> 调用函数的名称 </param>
        /// <returns> 函数指针 </returns>
        [DllImport("kernel32.dll")]
        private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

        /// <summary>
        ///     原型是 : BOOL FreeLibrary(HMODULE hModule);
        /// </summary>
        /// <param name="hModule"> 需释放的函数库模块的句柄 </param>
        /// <returns> 是否已释放指定的 Dll </returns>
        [DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)]
        protected static extern bool FreeLibrary(IntPtr hModule);

        public ConcurrentDictionary<EMarketID, List<StockInfo>> DicStockInfo =
            new ConcurrentDictionary<EMarketID, List<StockInfo>>();

        public static T DeserializeObject<T>(XmlNode xmlNode)
        {
            var xr = new XmlNodeReader(xmlNode);
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            try
            {
                T obj = (T)serializer.Deserialize(xr);
                xr.Close();
                return obj;
            }
            catch (Exception ex)
            {
                return default(T);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pHModule"></param>
        /// <param name="lpProcName"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private static Delegate Invoke(IntPtr pHModule, string lpProcName, Type t)
        {
            // 若函数库模块的句柄为空，则抛出异常 
            if (pHModule == IntPtr.Zero)
            {
                throw (new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));
            }
            // 取得函数指针 
            IntPtr farProc = GetProcAddress(pHModule, lpProcName);
            // 若函数指针，则抛出异常 
            if (farProc == IntPtr.Zero)
            {
                throw (new Exception(" 没有找到 :" + lpProcName + " 这个函数的入口点 "));
            }
            return Marshal.GetDelegateForFunctionPointer(farProc, t);
        }
        
        private readonly IntPtr _handle;
        
        #region Init 初始化

        private delegate int DelegateInit();

        /// <summary>
        /// 初始化
        /// </summary>
        /// <returns>0 表示成功，非0表示失败</returns>
        public int Init()
        {
            if (_isInit)
            {
                return 0;
            }
            var n   = ((DelegateInit)Invoke(_handle, "Init", typeof(DelegateInit)))();
            if (n == 0)
            {
                _isInit = true;
            }
            return n;
        }

        #endregion
        
        #region NewMultiLogin 用户登录

        private delegate int DelegateNewMultiLogin(string account, string name, string ip, int port);

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="account"></param>
        /// <param name="name"></param>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns>
        /// 0  表示连接服务器成功
        /// -1 表示连接服务器失败
        /// -2 表示该账号本地已登录
        /// -3 表示不正确的账号类型
        /// -1001 未初始化
        /// </returns>
        public int NewMultiLogin(string account, string name, string ip, int port)
        {
            if (!_isInit)
            {
                return -1001;
            }
            var n = ((DelegateNewMultiLogin) Invoke(_handle, "NewMultiLogin", typeof (DelegateNewMultiLogin)))(account,
                name, ip, port);
            if (n == 0)
            {
                _isLogin = true;
            }
            return n;
        }

        #endregion

        #region AskMarketStatus 查询市场状态

        private delegate int DelegateAskMarketStatus(int reqId, byte[] market, int size);

        /// <summary>
        /// 查询市场状态
        /// </summary>
        /// <param name="reqId"></param>
        /// <param name="market"></param>
        /// <returns>
        /// 0 表示成功
        /// -1 表示该账号没有登录服务器
        /// -2 发送指令失败
        /// </returns>
        public int AskMarketStatus(int reqId, EMarketID[] market)
        {
            var bMarket = market.Select(m => (byte)m).ToArray();
            var n = ((DelegateAskMarketStatus)Invoke(_handle, "AskMarketStatus", typeof(DelegateAskMarketStatus)))(
                reqId, bMarket, bMarket.Length);
            return n;
        }

        #endregion

        #region AskMarketTime 查询市场时间 不支持该查询

        private delegate int DelegateAskMarketTime(int reqId, byte[] market, int size);

        /// <summary>
        /// 查询市场状态 不支持该查询
        /// </summary>
        /// <param name="reqId"></param>
        /// <param name="market"></param>
        /// <returns></returns>
        public int AskMarketTime(int reqId, EMarketID[] market)
        {
            var bMarket = market.Select(m => (byte)m).ToArray();
            return ((DelegateAskMarketTime)Invoke(_handle, "AskMarketTime", typeof(DelegateAskMarketTime)))(
                reqId, bMarket, bMarket.Length);
        }

        #endregion

        #region AskMarketXmlInitAsk 查询市场股票信息和排序

        private delegate int DelegateAskMarketXmlInitAsk(int reqId, EMarketID marketId);


        /// <summary>
        /// 查询市场股票信息和排序
        /// </summary>
        /// <param name="reqId"></param>
        /// <param name="marketId"></param>
        /// <returns>
        /// 0 表示成功
        /// -1 表示该账号没有登录服务器
        /// -2 发送指令失败
        /// </returns>
        public int AskMarketXmlInitAsk(int reqId, EMarketID marketId)
        {
            return ((DelegateAskMarketXmlInitAsk)Invoke(_handle, "AskMarketXmlInitAsk", typeof(DelegateAskMarketXmlInitAsk)))(
                reqId, marketId);
        }

        #endregion

        #region AskStockQuote 订阅股票行情

        private delegate int DelegateAskStockQuote(int reqId, EMarketID marketId, string stockCode);

        /// <summary>
        /// 订阅股票行情
        /// </summary>
        /// <param name="reqId"></param>
        /// <param name="marketId"></param>
        /// <param name="stockCode"></param>
        /// <returns></returns>
        public int AskStockQuote(int reqId, EMarketID marketId, string stockCode)
        {
            return ((DelegateAskStockQuote)Invoke(_handle, "AskStockQuote", typeof(DelegateAskStockQuote)))(
                reqId, marketId, stockCode);
        }

        #endregion

        #region AskMarketPush 订阅全市场行情

        private delegate int DelegateAskMarketPush(int reqId, byte[] market, int size);

        /// <summary>
        /// 订阅全市场行情
        /// </summary>
        /// <param name="reqId"></param>
        /// <param name="market"></param>
        /// <returns>
        /// 0 表示成功
        /// -1 表示该账号没有登录服务器
        /// -2 发送指令失败
        /// </returns>
        public int AskMarketPush(int reqId, EMarketID[] market)
        {
            if (!_isLogin)
            {
                return -1;
            }
            var bMarket = market.Select(m => (byte) m).ToArray();
            return ((DelegateAskMarketPush)Invoke(_handle, "AskMarketPush", typeof(DelegateAskMarketPush)))(
                reqId, bMarket, bMarket.Length);
        }

        #endregion

        #region AskStockKLine 获取K线

        private delegate int DelegateAskStockKLine(int reqId, EMarketID market, string stockCode, EKLineType klineType);

        /// <summary>
        /// 获取K线
        /// </summary>
        /// <param name="reqId"></param>
        /// <param name="market"></param>
        /// <param name="stockCode"></param>
        /// <param name="klineType"></param>
        /// <returns></returns>
        public int AskStockKLine(int reqId, EMarketID market, string stockCode, EKLineType klineType)
        {
            return ((DelegateAskStockKLine)Invoke(_handle, "AskStockKLine", typeof(DelegateAskStockKLine)))(
                reqId, market, stockCode, klineType);
        }

        #endregion

        #region AskLogout 用户登出

        private delegate int DelegateAskLogout(string account);

        /// <summary>
        /// 用户登出
        /// </summary>
        /// <returns></returns>
        public int AskLogout(string account)
        {
            return ((DelegateAskLogout)Invoke(_handle, "AskLogout", typeof(DelegateAskLogout)))(account);
        }

        #endregion

        private delegate void Register(IntPtr pPtr);

        #region OnError 请求错误时的回调

        public delegate void DelegateOnError(int reqId, int code, string msg);

        private DelegateOnError _onError;

        /// <summary>
        /// 请求错误时的回调
        /// </summary>
        public event DelegateOnError OnError
        {
            add
            {
                _onError += value;
                (Invoke(_handle, "RegisterOnError", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onError));
            }
            remove
            {
                // ReSharper disable once DelegateSubtraction
                _onError -= value;
                (Invoke(_handle, "RegisterOnError", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onError));
            }
        }

        #endregion

        #region OnLoginAsk 登录请求的回调

        public delegate void DelegateOnLoginAsk(string account, int version);

        private DelegateOnLoginAsk _onLoginAsk;

        /// <summary>
        /// 登录请求的回调
        /// </summary>
        public event DelegateOnLoginAsk OnLoginAsk
        {
            add
            {
                _onLoginAsk += value;
                (Invoke(_handle, "RegisterOnLoginAsk", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onLoginAsk));
            }
            remove
            {
                // ReSharper disable once DelegateSubtraction
                _onLoginAsk -= value;
                (Invoke(_handle, "RegisterOnLoginAsk", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onLoginAsk));
            }
        }

        #endregion

        #region OnMarketStatusAsk 查询市场状态请求的回调

        public delegate void DelegateOnMarketStatusAsk(int reqId, MarketStatus status);

        private DelegateOnMarketStatusAsk _onMarketStatusAsk;

        /// <summary>
        /// 查询市场状态请求的回调
        /// </summary>
        public event DelegateOnMarketStatusAsk OnMarketStatusAsk
        {
            add
            {
                _onMarketStatusAsk += value;
                (Invoke(_handle, "RegisterOnMarketStatusAsk", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onMarketStatusAsk));
            }
            remove
            {
                // ReSharper disable once DelegateSubtraction
                _onMarketStatusAsk -= value;
                (Invoke(_handle, "RegisterOnMarketStatusAsk", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onMarketStatusAsk));
            }
        }

        #endregion

        #region OnMarketTimeAsk 查询市场状态请求的回调

        public delegate void DelegateOnMarketTimeAsk(int reqId, MarketTime status);

        private DelegateOnMarketTimeAsk _onMarketTimeAsk;

        /// <summary>
        /// 查询市场状态请求的回调
        /// </summary>
        public event DelegateOnMarketTimeAsk OnMarketTimeAsk
        {
            add
            {
                _onMarketTimeAsk += value;
                (Invoke(_handle, "RegisterOnMarketTimeAsk", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onMarketTimeAsk));
            }
            remove
            {
                // ReSharper disable once DelegateSubtraction
                _onMarketTimeAsk -= value;
                (Invoke(_handle, "RegisterOnMarketTimeAsk", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onMarketTimeAsk));
            }
        }

        #endregion

        #region OnMarketXmlInit 查询市场股票信息和排序的回调

        public delegate void DelegateOnMarketXmlInit(int reqId, string data);

        private DelegateOnMarketXmlInit _onMarketXmlInit;

        /// <summary>
        /// 查询市场股票信息和排序的回调
        /// </summary>
        public event DelegateOnMarketXmlInit OnMarketXmlInit
        {
            add
            {
                _onMarketXmlInit += value;
                (Invoke(_handle, "RegisterOnMarketXmlInit", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onMarketXmlInit));
            }
            remove
            {
                // ReSharper disable once DelegateSubtraction
                _onMarketXmlInit -= value;
                (Invoke(_handle, "RegisterOnMarketXmlInit", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onMarketXmlInit));
            }
        }

        #endregion

        #region OnStockQuote 订阅个股行情请求的回调

        public delegate void DelegateOnStockQuote(int reqId, IntPtr quote, int count);

        private DelegateOnStockQuote _onStockQuote;

        /// <summary>
        /// 订阅个股行情请求的回调
        /// </summary>
        public event DelegateOnStockQuote OnStockQuote
        {
            add
            {
                _onStockQuote += value;
                (Invoke(_handle, "RegisterOnStockQuote", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onStockQuote));
            }
            remove
            {
                // ReSharper disable once DelegateSubtraction
                _onStockQuote -= value;
                (Invoke(_handle, "RegisterOnStockQuote", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onStockQuote));
            }
        }

        #endregion

        #region OnStockQuote 订阅全市场行情请求的回调

        public delegate void DelegateOnMarketPush(EMarketID marketId, IntPtr quote, int count);

        private DelegateOnMarketPush _onMarketPush;

        /// <summary>
        /// 订阅全市场行情请求的回调
        /// </summary>
        public event DelegateOnMarketPush OnMarketPush
        {
            add
            {
                _onMarketPush += value;
                (Invoke(_handle, "RegisterOnMarketPush", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onMarketPush));
            }
            remove
            {
                // ReSharper disable once DelegateSubtraction
                _onMarketPush -= value;
                (Invoke(_handle, "RegisterOnMarketPush", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onMarketPush));
            }
        }

        #endregion

        #region OnStockQuote 获取K线数据

        public delegate void DelegateOnStockKLine(int reqId, IntPtr kline, int count);

        private DelegateOnStockKLine _onStockKLine;

        /// <summary>
        /// 获取K线数据
        /// </summary>
        public event DelegateOnStockKLine OnStockKLine
        {
            add
            {
                _onStockKLine += value;
                (Invoke(_handle, "RegisterOnStockKLine", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onStockKLine));
            }
            remove
            {
                // ReSharper disable once DelegateSubtraction
                _onStockKLine -= value;
                (Invoke(_handle, "RegisterOnStockKLine", typeof(Register)) as Register)(
                    Marshal.GetFunctionPointerForDelegate(_onStockKLine));
            }
        }

        #endregion
    }
}
